#include "coutputcontext.h"

#include "coutputaudiostream.h"
#include "coutputvideostream.h"

namespace buola { namespace media { namespace ffmpeg {

int COutputContext::WriteCB(void* pClosure, uint8_t* pBuf, int pSize)
{
    COutputContext *lCtx=reinterpret_cast<COutputContext*>(pClosure);

    CBuffer<uint8_t> lBuffer(pBuf,pSize);

    lBuffer.SetOffset(lCtx->mOutOffset);
    
    lCtx->mOutStream->PushBuffer(lBuffer);;
    lCtx->mOutOffset+=pSize;

    return pSize;
}
    
COutputContext::COutputContext(const std::string& pFormat)
{
    if(avformat_alloc_output_context2(&mCtx,nullptr,pFormat.c_str(),nullptr)<0)
        throw XInternal("can't create ffmpeg output context\n");
}

void COutputContext::Open(blackbox::CStreamOut<uint8_t> &pOut)
{
    mOutStream=&pOut;
    mOutOffset=0;
    mCtx->pb=avio_alloc_context(alloc_array<uint8_t>(4096),4096,1,this,nullptr,WriteCB,nullptr);
}

COutputAudioStream* COutputContext::NewAudioStream(const std::string& pCodec)
{
    return new COutputAudioStream(mCtx,pCodec);
}

COutputVideoStream* COutputContext::NewVideoStream(const std::string& pCodec, const CSize_i& pSize)
{
    return new COutputVideoStream(mCtx,pCodec,pSize);
}

void COutputContext::WriteHeader()
{
    avformat_write_header(mCtx,nullptr);
}

void COutputContext::WriteInterleaved(AVPacket* pPacket)
{
    int lRet=av_interleaved_write_frame(mCtx,pPacket);
    if(lRet<0) throw XInvalid("can't write frame");
}

void COutputContext::WriteTrailer()
{
    av_write_trailer(mCtx);
}


/*namespace ffmpeg*/ } /*namespace media*/ } /*namespace buola*/ }
